﻿using System;
using System.Collections.Generic;
using System.Text;

using Octopus.Logging;
using Octopus.Logging.Running;

namespace Octopus.Logging.Impl.Text
{
    public abstract class AppenderSkeleton:IAppender
    {
        protected AppenderSkeleton()
        {
        }
        ~AppenderSkeleton()
        {
            // An appender might be closed then garbage collected. 
            // There is no point in closing twice.
            if (!m_closed)
            {
                Close();
            }
        }

        #region 私有字段
        /// <summary>
        /// The name of this appender.
        /// </summary>
        /// <remarks>
        /// See <see cref="Name"/> for more information.
        /// </remarks>
        private string m_name;

        /// <summary>
        /// Flag indicating if this appender is closed.
        /// </summary>
        /// <remarks>
        /// See <see cref="Close"/> for more information.
        /// </remarks>
        private bool m_closed = false;

        /// <summary>
        /// The guard prevents an appender from repeatedly calling its own DoAppend method
        /// </summary>
        private bool m_recursiveGuard = false;
        #endregion

        #region 公开属性
        /// <summary>Gets or sets the name of this appender.</summary>
        public string Name
        {
            get { return m_name; }
            set { m_name = value; }
        }
        #endregion

        #region 待实现方法
        /// <summary>
        /// Subclasses of <see cref="AppenderSkeleton"/> should implement this method 
        /// to perform actual logging.
        /// </summary>
        /// <param name="loggingEvent">The event to append.</param>
        /// <remarks>
        /// <para>
        /// A subclass must implement this method to perform
        /// logging of the <paramref name="loggingEvent"/>.
        /// </para>
        /// <para>This method will be called by <see cref="AppenderSkeleton.DoAppend"/>
        /// if all the conditions listed for that method are met.
        /// </para>
        /// <para>
        /// To restrict the logging of events in the appender
        /// override the <see cref="PreAppendCheck()"/> method.
        /// </para>
        /// </remarks>
        abstract protected void Append(string content);
        #endregion

        #region 可重写方法
        /// <summary>
        /// Initialise the appender based on the options set
        /// </summary>
        virtual public void ActivateOptions()
        {
        }

        /// <summary>
        /// Is called when the appender is closed. Derived classes should override 
        /// this method if resources need to be released.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Releases any resources allocated within the appender such as file handles, 
        /// network connections, etc.
        /// </para>
        /// <para>
        /// It is a programming error to append to a closed appender.
        /// </para>
        /// </remarks>
        virtual public void OnClose()
        {
            // Do nothing by default
        }

        /// <summary>
        /// Called before <see cref="Append"/> as a precondition.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This method is called by <see cref="AppenderSkeleton.DoAppend"/>
        /// before the call to the abstract <see cref="Append"/> method.
        /// </para>
        /// <para>
        /// This method can be overridden in a subclass to extend the checks 
        /// made before the event is passed to the <see cref="Append"/> method.
        /// </para>
        /// <para>
        /// A subclass should ensure that they delegate this call to
        /// this base class if it is overridden.
        /// </para>
        /// </remarks>
        /// <returns><c>true</c> if the call to <see cref="Append"/> should proceed.</returns>
        virtual protected bool PreAppendCheck()
        {
            return true;
        }

        #endregion Implementation of IOptionHandler

        #region 公开实现
        /// <summary>
        /// Closes the appender and release resources.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Release any resources allocated within the appender such as file handles, 
        /// network connections, etc.
        /// </para>
        /// <para>
        /// It is a programming error to append to a closed appender.
        /// </para>
        /// <para>
        /// This method cannot be overridden by subclasses. This method 
        /// delegates the closing of the appender to the <see cref="OnClose"/>
        /// method which must be overridden in the subclass.
        /// </para>
        /// </remarks>
        public void Close()
        {
            // This lock prevents the appender being closed while it is still appending
            lock (this)
            {
                if (!m_closed)
                {
                    OnClose();
                    m_closed = true;
                }
            }
        }


        public virtual void Init(LoggerRuningContext config, IVolatileConfigParser parser)
        {
            ActivateOptions();
            _IsInitCompleted = true;
        }

        public bool DoAppend(string content)
        {
            // This lock is absolutely critical for correct formatting
            // of the message in a multi-threaded environment.  Without
            // this, the message may be broken up into elements from
            // multiple thread contexts (like get the wrong thread ID).

            lock (this)
            {
                if (m_closed)
                {
                    return false;
                }

                // prevent re-entry
                if (m_recursiveGuard)
                {
                    return false;
                }

                try
                {
                    m_recursiveGuard = true;
                    this.Append(content);
                }
                catch
                {
                    throw;
                }
                finally
                {
                    m_recursiveGuard = false;
                }
            }
            return true;
        }

        #endregion

        bool _IsInitCompleted;
        public bool IsInitCompleted
        {
            get { return _IsInitCompleted; }
        }
    }
}
